#include "NoSpread.h"

NoSpread g_pNoSpread;

void NoSpread::Init()
{
	Active = false;
	NoRecoil = true;
	RCS = false;
	NoSpreadMethod = false;
	SpreadFix = SD_Tools::Angle();
}

float NoSpread::RandomFloat(float min, float max)
{
	typedef float (* RandomFloat_t)(float,float);
	static RandomFloat_t m_RandomFloat = (RandomFloat_t)GetProcAddress(GetModuleHandle(L"vstdlib.dll"), "RandomFloat");
	return m_RandomFloat(min,max);
}

void NoSpread::RandomSeed(UINT seed)
{
	typedef void (* RandomSeed_t)(UINT);
	static RandomSeed_t m_RandomSeed = (RandomSeed_t)GetProcAddress(GetModuleHandle(L"vstdlib.dll"), "RandomSeed");
	m_RandomSeed(seed);
	return;
}

void NoSpread::GetSpreadXY(UINT seed, SD_Tools::Vector & qAngle)
{
	seed = seed & 255;
	seed++;
	RandomSeed(seed);

	Entity* pLocal = g_pInterfaces.g_pEntList->GetClientEntity(g_pInterfaces.g_pEngine->GetLocalPlayer());
	if(!pLocal)
		return;

	CBaseCombatWeapon* pWeapon = GameUtilities::GetBaseCombatWeapon(pLocal->GetBaseEntity());
	if (!pWeapon)
		return;

	//pWeapon->UpdateAccuracyPenalty();

	float Spread[2];
	Spread[0] = pWeapon->GetSpread();
	Spread[1] = pWeapon->GetInaccuracy();

	float Randoms[4];
	Randoms[0] = RandomFloat(0.0f, 2.0f * SD_Tools::SD_PI_F);
	Randoms[1] = RandomFloat(0.0f, Spread[0]);
	Randoms[2] = RandomFloat(0.0f, 2.0f * SD_Tools::SD_PI_F);
	Randoms[3] = RandomFloat(0.0f, Spread[1]);

	qAngle.x = (cos(Randoms[0]) * Randoms[1]) + (cos(Randoms[2]) * Randoms[3]);
	qAngle.y = (sin(Randoms[0]) * Randoms[1]) + (sin(Randoms[2]) * Randoms[3]);
}

void NoSpread::GetSpreadFix( UINT Seed, SD_Tools::Angle &vIn, SD_Tools::Angle* vOut )
{
	if (Active && !NoSpreadMethod)
	{
		SD_Tools::Vector vF,vR,vU,vDir;
		SD_Tools::Vector View,Spread;
		SD_Tools::Angle Dest;

		SD_Tools::MathHelper::AngleToVectors(vIn,&vF,&vR,&vU);

		GetSpreadXY(Seed,Spread);

		vDir.x = vF.x + Spread.x * vR.x + Spread.y * vU.x;
		View.x = 8192.0f * vDir.x;
		vDir.y = vF.y + Spread.x * vR.y + Spread.y * vU.y;
		View.y = 8192.0f * vDir.y;
		vDir.z = vF.z + Spread.x * vR.z + Spread.y * vU.z;
		View.z = 8192.0f * vDir.z;

		View.ToAngles(&Dest);

		vOut->x = vIn.x - Dest.x;
		vOut->y = vIn.y - Dest.y;
		vOut->z = 0;
	}
	else
	{
		vOut->x = 0.0f;
		vOut->y = 0.0f;
		vOut->z = 0.0f;
	}
}

void NoSpread::ApplyNoRecoil( CUserCmd* cmd, bool dual /*= false*/ )
{
	if (Active)
	{
		static SD_Tools::Vector LastRecoil(0, 0, 0);
		Entity* pMe = g_pInterfaces.g_pEntList->GetClientEntity(g_pInterfaces.g_pEngine->GetLocalPlayer());

		if (!pMe)
		{
			return;
		}

		if (pMe->iTeamNum() == TeamSpec)
		{
			return;
		}

		SD_Tools::Vector* punch = pMe->getRecoilVec();

		if (NoRecoil)
		{
			if (dual)
			{
				cmd->viewangles.Pitch -= punch->x;
				cmd->viewangles.Yaw -= punch->y;
				GameUtilities::FixAngle(&cmd->viewangles);
				if(g_pAimbot.Silent)
				{
					SD_Tools::Angle Temp;
					g_pInterfaces.g_pEngine->GetViewAngles(&Temp);
					Temp.x -= punch->x - LastRecoil.x;
					Temp.y -= punch->y - LastRecoil.y;
					g_pInterfaces.g_pEngine->SetViewAngles(Temp);
					LastRecoil = *punch;
				}
				else
				{
					g_pInterfaces.g_pEngine->SetViewAngles(cmd->viewangles);
				}
				cmd->viewangles.Pitch -= punch->x * 0.92f;
				cmd->viewangles.Yaw -= punch->y * 0.92f;
				GameUtilities::FixAngle(&cmd->viewangles);
			}
			else
			{
				SD_Tools::Angle Temp;

				g_pInterfaces.g_pEngine->GetViewAngles(&Temp);
				Temp.x -= punch->x - LastRecoil.x;
				Temp.y -= punch->y - LastRecoil.y;
				GameUtilities::FixAngle(&Temp);
				g_pInterfaces.g_pEngine->SetViewAngles(Temp);
				cmd->viewangles.Pitch = Temp.x - punch->x * 0.92f;
				cmd->viewangles.Yaw = Temp.y - punch->y * 0.92f;
				GameUtilities::FixAngle(&cmd->viewangles);

				LastRecoil = *punch;
			}
			cmd->viewangles.Roll = 0.0f;
		}
		else if (RCS)
		{
			static float LastCorrection = 0.0f;
			SD_Tools::Angle Temp;
			float Correction;

			g_pInterfaces.g_pEngine->GetViewAngles(&Temp);

			float NeededCorrection = punch->x*1.92f;
			float DoCorrection = LastCorrection + (NeededCorrection-LastCorrection)*0.666f;

			Correction = DoCorrection;
			Temp.x -= Correction - LastCorrection;

			g_pInterfaces.g_pEngine->SetViewAngles(Temp);

			LastCorrection = Correction;
			LastRecoil = *punch;
		}

	}
}

void NoSpread::Enable()
{
	Active = true;
}

void NoSpread::Disable()
{
	Active = false;
}

void NoSpread::Set( bool Active )
{
	this->Active = Active;
}

void NoSpread::SetMethod( bool Method )
{
	NoSpreadMethod = Method;
}

void NoSpread::SetRecoil( bool Active )
{
	NoRecoil = Active;
}

void NoSpread::SetRCS( bool Active )
{
	this->RCS = Active;
}

void NoSpread::ApplySeedSpread( CUserCmd* cmd )
{
	if (Active && NoSpreadMethod)
	{
		cmd->random_seed = 165;
		cmd->command_number = 2087;
	}
}
